package lingou.homework.postbar.controller.tool;

import jakarta.servlet.http.HttpSession;
import lingou.homework.postbar.exception.SystemException;
import lingou.homework.postbar.handler.SessionHandler;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.PrintStream;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class LogPrinter {
    @Value("${postbar-config.log-file:false}")
    Boolean toFile;
    @Value("${postbar-config.log-cache-size:40}")
    Integer outputSize;
    private PrintStream printStream;
    private StringBuffer stringBuffer = new StringBuffer();
    private Map<HttpSession, List<String>> cacheMap = new HashMap<>();
//    private volatile boolean changed;
    private static File createLog(){
        File dir = new File("logs");
        if(!dir.exists()) {
            System.out.println(dir.mkdir());
        }
        SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd_HHmmss");
        dateFormat.setTimeZone(TimeZone.getTimeZone("Asia/Shanghai"));
        File file = new File("logs/" + dateFormat.format(new Date(System.currentTimeMillis())) + ".log");
        try {
            file.createNewFile();
        } catch (IOException e) {
            throw new SystemException(e);
        }
        return file;
    }
    private PrintStream getLogPrinter(){
        if(printStream == null){
            if(toFile) {
                try {
                    printStream = new PrintStream(createLog());
                } catch (FileNotFoundException e) {
                    throw new RuntimeException(e);
                }
            }
            else printStream = System.out;
        }
        return printStream;
    }
    public void println(Object...strs){
        printlnDepth(0, strs);
    }
    public void printlnDepth(int depth, Object...strs){
        for (Object str : strs) {
            append(objToString(str));
        }
        flush(depth);
    }
    public void print(Object str) {
        append(objToString(str));
    }
    public String getCache(HttpSession session){
        registerListener(session);
//        if(!changed) return null;
        List<String> cache = cacheMap.get(session);
        if(cache.size() == 0) return null;
        StringBuilder stringBuilder = new StringBuilder();
        cache.forEach(x -> stringBuilder.append(x).append("\n<br/>"));
        cache.clear();
//        this.changed = false;
        return stringBuilder.toString();
    }

    public void registerListener(HttpSession session){
        if(!cacheMap.containsKey(session)) cacheMap.put(session, new ArrayList<>());
    }

    private String objToString(Object object){
        if(object == null) return "null";
        else return object.toString();
    }
    private void append(String str) {
        stringBuffer.append(str).append(' ');
    }
    private void flush(int depth){
        while ((depth--) > 0) stringBuffer.insert(0, "    ");
        String x = stringBuffer.toString();
        getLogPrinter().println(x);
        appendToOutputList(x);
        stringBuffer.setLength(0);
//        changed = true;
    }
    private void appendToOutputList(String str){
        ArrayList<HttpSession> toDelete = new ArrayList<>();
        cacheMap.forEach((session, cache)->{
//            System.out.println(session);
            if(session == null ||
                    System.currentTimeMillis() - ((long) session.getAttribute("lastDebug")) > 4000){
                toDelete.add(session);
            }
            else {
                cache.add(str);
                if(cache.size() > outputSize) cache.remove(0);
            }
        });
        toDelete.forEach(x -> cacheMap.remove(x));
    }
}
